package com.apchernykh.rozhlasapp.services;

import java.security.InvalidParameterException;

import com.apchernykh.player.RozhlasWidgetProvider;
import com.apchernykh.rozhlasapp.player.IPlaybackService;
import com.apchernykh.rozhlasapp.ui.RozhlasAppBaseFragmentActivity;
import com.apchernykh.rozhlasapp.utils.ConditionalLog;
import com.apchernykh.types.ApplicationModel.EPlaybackStatuses;
import com.apchernykh.types.DetailedUrl;
import com.apchernykh.types.StationInfo;

import android.content.Context;
import android.content.Intent;
import android.os.Binder;
import android.os.IBinder;
import android.support.v4.app.ServiceCompat;
import android.widget.Toast;

public class BackgroundPlaybackService extends
		BackgroundPhoneInetNotifiedService implements IPlaybackService {

	EPlaybackStatuses mPlaybackStatus = EPlaybackStatuses.STOPPED;
	EPlaybackStatuses mPlaybackStatusSinceLastIncomingCall = EPlaybackStatuses.STOPPED;
	private DetailedUrl mCurrentStationInfo;
	private static final String mLostFocusObject = "FocusControlsPlayback";

	// Handler that receives messages from the thread
	private final IBinder mBinder = new LocalBinder();

	@Override
	public void onDestroy() {
		if (mLocalHandler.mPlayerWrapper.isActive()) {
			// todo:remove this hack
			mLocalHandler.mPlayerWrapper.stop();
			ConditionalLog.e("onDestroy disconnected");
		}
		super.onDestroy();
	}

	private int mRecentStartId = -1;

	@Override
	public void onInetConnectivityChange(boolean mInetIsAvailable) {
		// ConditionalLog.e("onInetConnectivityChange",
		// "inet connectivity " + String.valueOf(mInetIsAvailable));
		RozhlasAppBaseFragmentActivity.mApplicationModel.mOnInetStateListener
				.onInetStatusChange(mInetIsAvailable);
		if (!mInetIsAvailable) {
			stopPlayback();
		}
	}

	@Override
	public int onStartCommand(Intent iIntent, int iFlags, int iStartId) {
		if (iIntent != null) {
			ConditionalLog.e("onStartCommand " + iIntent.toString());
			mRecentStartId = iStartId;
			handlePlaybackCommand(iIntent, iStartId);
		}
		return ServiceCompat.START_STICKY;
	}

	private void handlePlaybackCommand(Intent iIntent, final int iStartId) {
		if (iIntent != null && iIntent.getAction() != null) {
			if (iIntent.getAction().equals(ACTION_PLAYBACK_STOP)) {
				if (getPlaybackStatus() != EPlaybackStatuses.STOPPED) {
					stopPlayback();
				}
			}
			if (iIntent.getAction().equals(ACTION_PLAYBACK_START)) {
				startMostRecentStationInBackground();
				// stopSelf(startId);
			}
			if (iIntent.getAction().equals(ACTION_PLAYBACK_KEEPALIVE)) {
				mLocalHandler.postDelayed(new Runnable() {

					@Override
					public void run() {
			
						stopSelf(iStartId);
					}

				}, 2000);

			}
		}
	}

	private void startMostRecentStationInBackground() {
		DetailedUrl aPlayTarget = new DetailedUrl(mPreferences.mLastStationURL,
				mPreferences.mLastStationName);
		if (getPlaybackStatus() == EPlaybackStatuses.STOPPED) {
			startPlayback(aPlayTarget);
			enableBackgroundPlayback();
		}
	}

	public class LocalBinder extends Binder {
		BackgroundPlaybackService getService() {
			// Return this instance of LocalService so clients can call public
			// methods
			return BackgroundPlaybackService.this;
		}
	}

	@Override
	public IBinder onBind(Intent iIntent) {
		return mBinder;
	}

	@Override
	public EPlaybackStatuses getPlaybackStatus() {
		return mPlaybackStatus;
	}

	@Override
	public void enableBackgroundPlayback() {
		if (mCurrentStationInfo != null) {
			setNotification(mCurrentStationInfo.mTitle,
					mCurrentStationInfo.mDescription);
		}
		else
		{
			ConditionalLog.e("Could not enable background playback");
		}
	}

	@Override
	public void disableBackgroundPlayback() {
		stopForegroundCompat(ONGOING_NOTIFICATION);
		notifyGuiOnPlaybackState();
	}

	@Override
	public void startPlayback(DetailedUrl iDetailedUrl) {
		if (mConnectivity.isInetAvailable()
				&& (mPlaybackStatus == EPlaybackStatuses.STOPPED || mPlaybackStatus == EPlaybackStatuses.PAUSED_WAIT_PHONE_HANG)) {
			mCurrentStationInfo = iDetailedUrl;
			mPlaybackStatus = EPlaybackStatuses.CONNECTION_IN_PROGRESS;
			reScheduleImmediate(PlaybackAsyncControlHandler.START_PLAYBACK,
					iDetailedUrl);
			notifyGuiOnPlaybackState();
		}
	}

	@Override
	public void startPlayback(StationInfo iStationInfo) {
		DetailedUrl aPlayTarget = new DetailedUrl(iStationInfo,
				mPreferences.mDesiredBitrate);
		mPreferences.mLastStationName = aPlayTarget.mTitle;
		mPreferences.mLastStationURL = aPlayTarget.mUrl;
		final Context aServiceRef = this;
		mLocalHandler.post(new Runnable() {
			@Override
			public void run() {
				mPreferences.save(aServiceRef);
			}
		});
		startPlayback(aPlayTarget);
	}

	@Override
	public DetailedUrl getExtendedPlaybackInfo() {
		if (mPlaybackStatus == EPlaybackStatuses.STOPPED) {
			throw new InvalidParameterException(
					"Can only return playback info when playing or preparing");
		}
		return mCurrentStationInfo;
	};

	@Override
	public void stopPlayback() {
		reScheduleImmediate(PlaybackAsyncControlHandler.STOP_PLAYBACK, " ");
		onPlaybackStatusChanged(EPlaybackStatuses.STOPPED);
	}

	public void pausePlayback() {
		reScheduleImmediate(PlaybackAsyncControlHandler.PAUSE_PLAYBACK, " ");
		onPlaybackStatusChanged(EPlaybackStatuses.PAUSED_WAIT_PHONE_HANG);
	}

	public void pausePlaybackOnIncomingCall() {
		// Phone going off-hook or ringing, pause the player.
		if (mPlaybackStatus != EPlaybackStatuses.STOPPED) {
			mPlaybackStatusSinceLastIncomingCall = mPlaybackStatus;
			mPlaybackStatus = EPlaybackStatuses.PAUSED_WAIT_PHONE_HANG;
			pausePlayback();
		}
	}

	public void resumePlaybackOnPhoneHangUp() {
		// Phone idle. Rewind a couple of seconds and start playing.
		if (mPlaybackStatusSinceLastIncomingCall != EPlaybackStatuses.STOPPED) {
			if (mCurrentStationInfo != null) {
				startPlayback(mCurrentStationInfo);
			}
			mPlaybackStatusSinceLastIncomingCall = EPlaybackStatuses.STOPPED;
		}
	}

	private void notifyGuiOnPlaybackState() {
		ConditionalLog.e("New Playback State "
				+ String.valueOf(mPlaybackStatus));
		RozhlasAppBaseFragmentActivity.mApplicationModel.mOnPlaybackStateListener
				.onPlaybackStatusChange(mPlaybackStatus);
		RozhlasWidgetProvider.onPlaybackStatusChange(mPlaybackStatus, this,
				mPreferences);
	}

	@Override
	public void reScheduleViewExpiration(long aNextRefresh) {
		reScheduleViewsExpiration(aNextRefresh);
	}

	@Override
	public void cancelViewExpiration() {
		cancelViewsExpiration();
	}

	@Override
	public boolean isBackgroundEnabled() {
		return mBackgroundEnabled;
	}
	
	@Override
	public void onLostFocus() {
		if (!mBackgroundEnabled) {
			reScheduleDelayed(1000, PlaybackAsyncControlHandler.STOP_PLAYBACK, mLostFocusObject);
		}
	}

	@Override
	public void onReceivedFocus() {
		if (!mBackgroundEnabled) {
			cancelMessage(PlaybackAsyncControlHandler.STOP_PLAYBACK, mLostFocusObject);
		}
	}

	@Override
	public void onScreenOn() {
	}

	@Override
	public void onScreenOff() {		
		cancelMessage(PlaybackAsyncControlHandler.STOP_PLAYBACK, mLostFocusObject);
		enableBackgroundPlayback();
	}

	
	@Override
	public void onPlaybackStatusChanged(EPlaybackStatuses iNewStatus) {
		if (mPlaybackStatus != iNewStatus
				&& iNewStatus == EPlaybackStatuses.STOPPED) {
			mCurrentStationInfo = null;
			disableBackgroundPlayback();
		}
		mPlaybackStatus = iNewStatus;
		notifyGuiOnPlaybackState();
	}

	@Override
	public void onError() {
		Toast.makeText(this, "onError - error occured", Toast.LENGTH_LONG)
				.show();
		errorDetected();
		stopPlayback();
	}

	@Override
	public void onPrepareProgressChanged(int iNewProgress) {
		// for the moment, we use this code only to switch from
		// CONNECTION_IN_PROGRESS to PLAYING
		if (getPlaybackStatus() == EPlaybackStatuses.CONNECTION_IN_PROGRESS) {
			ConditionalLog
					.e("player progress: " + String.valueOf(iNewProgress));
			if (iNewProgress > 99) {
				onPlaybackStatusChanged(EPlaybackStatuses.PLAYING);
			}
		}
	}

	@Override
	public void onPleaseRetry(DetailedUrl iURL) {
		if (mConnectivity.isInetAvailable()) {
			reScheduleImmediate(PlaybackAsyncControlHandler.START_PLAYBACK,
					iURL);
		}
	}

	@Override
	public void onPreferencesChanged() {
		mPreferences.refresh(this);
		RozhlasAppBaseFragmentActivity.mApplicationModel.mOnInetStateListener
				.onInetStatusChange(mConnectivity.isInetAvailable());
	}

	@Override
	public void goStopYourself() {
		ConditionalLog.e("goStopYourself");
		stopSelf(mRecentStartId);
		mRecentStartId = -1;
	}
}
